/**
 * is用于判断类型是否满足需求
 * @param {any} value 需要校验的值
 * @param {string} type 校验的类型
 * */
export const is = function(value: any, type: string): boolean
{
    // return toString.call(val) === `[object ${type}]`;
    return Object.prototype.toString.call(value) === `[object ${type}]`;
};

/**
 * 判断是否为数字类型
 * @param {any} value 传递需要检验的值
 * */
export const isNumber = function(value: any): value is number
{
    // return value.constructor === Number;
    // return Object.prototype.toString.call(value) === "[object Number]";
    return is(value, "Number");
};

/**
 * 判断是否为对象类型
 * @param {any} value 传递需要检验的值
 * */
export const isObject = function(value: any): value is Record<string, any>
{
    // return value.constructor === Object;
    // return Object.prototype.toString.call(value) === "[object Object]";
    return value !== null && is(value, "Object");
};

/**
 * 判断是否为数组类型
 * @param {any} value 传递需要检验的值
 * */
export const isArray = function(value: any): value is Array<any>
{
    // return value.constructor === Array;
    // return Object.prototype.toString.call(value) === "[object Array]";
    return value !== null && is(value, "Array");
};

/**
 * 判断是否为字符串
 * @param {any} value 传递需要检验的值
 * */
export const isString = function(value: any): value is string
{
    // return value.constructor === String;
    // return Object.prototype.toString.call(value) === "[object String]";
    return is(value, "String");
};

/**
 * 判断是否为函数
 * @param {any} value 传递需要检验的值
 * */
export const isFunction = function(value: any): value is Function
{
    // return value.constructor === Function;
    // return Object.prototype.toString.call(value) === "[object Function]";
    return is(value, "Function");
};

/**
 * 判断是否为布尔
 * @param {any} value 传递需要检验的值
 * */
export const isBoolean = function(value: any): value is boolean
{
    // return value.constructor === Boolean;
    // return Object.prototype.toString.call(value) === "[object Boolean]";
    return is(value, "Boolean");
};

/**
 * 判断是否为空对象
 * @param {any} value 传递需要检验的值
 * */
export const isEmpty = function <T = unknown>(value: T): boolean
{
    // return JSON.stringify(value) === "{}";

    if (isArray(value))
    {
        return value.length === 0;
    }
    else if (isObject(value))
    {
        return Object.keys(value).length === 0;
    }
    else if (value instanceof Map || value instanceof Set)
    {
        return value.size === 0;
    }
    else
    {
        return false;
    }
};

/**
 * 判断两个对象是否相等
 * @param {object | array | string | number} first 第一个参数对象
 * @param {object | array | string | number} second 第二个参数对象
 * */
export const isEqual = function(first?: Record<string, any> | Array<any> | string | number, second?: Record<string, any> | Array<any> | string | number): boolean
{
    // 首先判断两个都是一样的对象
    if (isObject(first) && isObject(second))
    {
        const firstData = first as Record<string, any>;

        const secondData = second as Record<string, any>;

        const keys1 = Object.keys(firstData);

        const keys2 = Object.keys(secondData);

        // 比较key的长度
        if (keys1.length !== keys2.length)
        {
            return false;
        }

        // 遍历对象,看对象的值是否相等
        for (const k in firstData)
        {
            if (isObject(firstData[k]) && isObject(secondData[k]) || isArray(firstData[k]) && isArray(secondData[k]))
            {
                if (!isEqual(firstData[k], secondData[k]))
                {
                    return false;
                }
            }
            else if (firstData[k] !== secondData[k])
            {
                return false;
            }
        }

        return true;
    }
    else if (isArray(first) && isArray(second))
    {
        const firstData = first as any[];

        const secondData = second as any[];

        if (firstData.length !== secondData.length)
        {
            return false;
        }

        const length = firstData.length;

        for (let i = 0; i < length; i++)
        {
            const firstValue = firstData[i];

            if (isObject(firstData[i]) && isObject(secondData[i]) || isArray(firstData[i]) && isArray(secondData[i]))
            {
                if (!isEqual(firstData[i], secondData[i]))
                {
                    return false;
                }
            }
            // 当前值不出现在另一个数组内,则为假
            else if (!secondData.includes(firstValue))
            {
                return false;
            }
        }

        return true;
    }
    else if (isString(first) && isString(second) || isNumber(first) && isNumber(second))
    {
        return first === second;
    }
    else
    {
        return typeof first === typeof second;
    }
};